using System;
using System.Collections.Generic;
using System.IO;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
//using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Storage;

namespace Spacer {
	public class Main : Microsoft.Xna.Framework.Game {
		// Instance variables
		static List<Entity> s_listEntities = new List<Entity>();
		public static List<Entity> Entities {
			get { return s_listEntities; }
		}

		static Dictionary<string,Texture2D> s_dictTextures = new Dictionary<string,Texture2D>();
		public static Dictionary<string,Texture2D> Textures {
			get { return s_dictTextures; }
		}

		static Dictionary<string,Sprite> s_dictSprites = new Dictionary<string,Sprite>();
		public static Dictionary<string,Sprite> Sprites {
			get { return s_dictSprites; }
		}

		static Dictionary<string,SoundEffect> s_dictSoundEffects = new Dictionary<string,SoundEffect>();
		public static Dictionary<string,SoundEffect> SoundEffects {
			get { return s_dictSoundEffects; }
		}

		static Dictionary<string,SoundScript> s_dictSoundScripts = new Dictionary<string,SoundScript>();
		public static Dictionary<string,SoundScript> SoundScripts {
			get { return s_dictSoundScripts; }
		}

		static Dictionary<string,SpriteFont> s_dictFonts = new Dictionary<string,SpriteFont>();
		public static Dictionary<string,SpriteFont> Fonts {
			get { return s_dictFonts; }
		}

		static Dictionary<object,List<FarseerPhysics.Common.Vertices>> s_dictPhysicsMeshes = new Dictionary<object,List<FarseerPhysics.Common.Vertices>>();
		public static Dictionary<object,List<FarseerPhysics.Common.Vertices>> PhysicsMeshes {
			get { return s_dictPhysicsMeshes; }
		}

		// Main variables
		private GraphicsDeviceManager GraphicsMgr { get; set; }
		private List<float> FrameTimes { get; set; }
		bool GamerServicesFirstUpdateRan { get; set; }

		// ----------

		public Main() {
			Exiting += new EventHandler<EventArgs>( Shutdown );
			GraphicsMgr = new GraphicsDeviceManager(this);
			FrameTimes = new List<float>();

			GraphicsMgr.PreferMultiSampling = true;
		}

		// ----------

		protected override void Initialize() {
			// Initialized GamerServices - XBOX360
			if( Globals.Platform == Platform.XBOX360 || Globals.MessageBox(IntPtr.Zero,"Would you like to enable GamerServices?","XBox Live Proxy",(uint)MessageBoxButtons.YesNo) == (uint)DialogResult.Yes )
				Globals.GamerServicesEnabled = true;

			if( Globals.GamerServicesEnabled ) {
				//SignedInGamer.SignedIn += new EventHandler<SignedInEventArgs>( GamerSignedIn );
				//SignedInGamer.SignedOut += new EventHandler<SignedOutEventArgs>( GamerSignedOut );

				GamerServicesDispatcher.WindowHandle = Window.Handle;
				GamerServicesDispatcher.Initialize( Services );
			}

			// Init config
			Configuration.Initialize();

			// Init game
			base.Initialize();
			
			// Init the rest
			Input.Initialize();
			Surface.Initialize( GraphicsDevice );
			Globals.Initialize( this );
			Network.Initialize();
			
			ApplyScreenSettings();

			#if !XBOX360
			IsMouseVisible = true;
			#endif
		}

		protected void Shutdown( Object s, EventArgs e ) {
			Input.SaveBindings();
			Configuration.Save();
		}

		// ----------

		protected override void LoadContent() {
			DirectoryInfo dirinfo;
			FileInfo[] files;

			Content.RootDirectory = Configuration.ContentPath;

			// Debug textures
			Texture2D missing = new Texture2D( GraphicsDevice, 64, 64 );
			Color[] data = new Color[64*64];
			for(int y=0;y<64;y++) {
				for(int x=0;x<64;x++) {
					bool cx = (x / 8) % 2 == 0;
					bool cy = (y / 8) % 2 == 1;
					if( cy )
						cx = !cx;
					data[y*64+x] = (cx ? Color.Fuchsia : Color.Black);
				}
			}
			missing.SetData<Color>( data );
			s_dictTextures["Missing"] = missing;

			Texture2D debug = new Texture2D( GraphicsDevice, 1, 1 );
			debug.SetData<Color>( new Color[]{Color.White} );
			s_dictTextures["White"] = debug;

			// Load the rest of the textures
			dirinfo = new DirectoryInfo( ".\\"+Configuration.ContentPath+"\\Textures\\" );
			if( dirinfo.Exists ) {
				files = dirinfo.GetFiles();
				foreach(FileInfo f in files) {
					string name = Path.GetFileNameWithoutExtension( f.Name );
					string path = "Textures\\" + name;
					s_dictTextures[name] = Content.Load<Texture2D>( path );
					s_dictTextures[name].Name = name;
				}
			}
			
			// Load the sprites
			dirinfo = new DirectoryInfo( ".\\"+Configuration.ContentPath+"\\Sprites\\" );
			if( dirinfo.Exists ) {
				files = dirinfo.GetFiles();
				foreach(FileInfo f in files) {
					string name = Path.GetFileNameWithoutExtension( f.Name );
					s_dictSprites[name] = new Sprite( name );
				}
			}
			
			// Load the sounds
			dirinfo = new DirectoryInfo( ".\\"+Configuration.ContentPath+"\\Sounds\\" );
			if( dirinfo.Exists ) {
				files = dirinfo.GetFiles();
				foreach(FileInfo f in files) {
					string name = Path.GetFileNameWithoutExtension( f.Name );
					string path = "Sounds\\" + name;
					s_dictSoundEffects[name] = Content.Load<SoundEffect>( path );
				}
			}
			
			// Load the sound scripts
			dirinfo = new DirectoryInfo( ".\\"+Configuration.ContentPath+"\\Scripts\\" );
			if( dirinfo.Exists ) {
				files = dirinfo.GetFiles();
				foreach(FileInfo f in files) {
					string name = Path.GetFileNameWithoutExtension( f.Name );
					s_dictSoundScripts[name] = new SoundScript( name );
				}
			}

			// Load the fonts
			dirinfo = new DirectoryInfo( ".\\"+Configuration.ContentPath+"\\Fonts\\" );
			if( dirinfo.Exists ) {
				files = dirinfo.GetFiles();
				foreach(FileInfo f in files) {
					string name = Path.GetFileNameWithoutExtension( f.Name );
					string path = "Fonts\\" + name;
					s_dictFonts[name] = Content.Load<SpriteFont>( path );
				}
			}
		}

		protected override void UnloadContent() {
		}

		// ----------

		protected override void Update( GameTime gameTime ) {
			// GameTime
			Globals.GameTime = (float)gameTime.TotalGameTime.TotalSeconds;
			Globals.UpdateDeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

			// Update Modules
			if( Globals.GamerServicesEnabled ) {
				GamerServicesDispatcher.Update();

				// If no signed in gamers, sign in
				if( !GamerServicesFirstUpdateRan ) {
					GamerServicesFirstUpdateRan = true;
					if( SignedInGamer.SignedInGamers.Count == 0 )
						Guide.ShowSignIn( 1, false );
				}
			}

			if( Globals.LocalStorage == null )
				Helper.GetStorageDevice( device => { Globals.LocalStorage = Helper.GetStorageContainer((StorageDevice)device); } );

			Input.Update( gameTime );
			Network.Update();

			if( Globals.CurrentSession != null )
				Globals.CurrentSession.UpdateSolarSystems();

			// Update top Activity
			foreach(Activity top in Globals.CurrentActivities()) {	

				if( top.IsFinished() && top == Globals.CurrentActivity ) {
					Globals.PopActivity();
					continue;
				}

				// Have to check if top exists again just in-case it changed above
				if( top != null )
					top.Update();

			}
			
			base.Update( gameTime );
		}

		protected override void Draw( GameTime gameTime ) {
			// GameTime
			Globals.GameTime = (float)gameTime.TotalGameTime.TotalSeconds;
			Globals.DrawDeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

			// Framerate
			float average = 0f;
			FrameTimes.Add( Globals.DrawDeltaTime );
			if( FrameTimes.Count > 10 )
				FrameTimes.RemoveAt( 0 );
			foreach(float f in FrameTimes)
				average += f;
			average /= 10f;

			GraphicsDevice.Clear( Color.Black );

			// Draw top Activity
			foreach(Activity top in Globals.CurrentActivities()) {
				
				Spacer.Surface.BeginWorld();
				top.DrawWorld();
				Spacer.Surface.End();

				Spacer.Surface.BeginOverlay();
				top.DrawOverlay();

				Surface.DrawColor = Color.White;
				Surface.DrawString( "Default", "FPS: "+(1f/average), new Vector2(Surface.Width-5f,0f), new Vector2(1f,0f), 0, -Layer.LAYER_20 );

				Spacer.Surface.End();

			}

			base.Draw( gameTime );
		}

		
		// ----------

		private void ApplyScreenSettings() {
			GraphicsMgr.IsFullScreen = (Globals.Platform == Platform.XBOX360 ? true : Configuration.Fullscreen);
			if( GraphicsMgr.IsFullScreen ) {
				GraphicsMgr.PreferredBackBufferWidth = Configuration.FSResolutionWidth;
				GraphicsMgr.PreferredBackBufferHeight = Configuration.FSResolutionHeight;
			} else {
				GraphicsMgr.PreferredBackBufferWidth = Configuration.ResolutionWidth;
				GraphicsMgr.PreferredBackBufferHeight = Configuration.ResolutionHeight;
			}
			GraphicsMgr.ApplyChanges();
		}

		public static Texture2D FindTexture( string strTexture ) {
			Texture2D buffer;
			if( s_dictTextures.TryGetValue(strTexture,out buffer) )
				return buffer;
			return s_dictTextures["Missing"];
		}

		public static Sprite FindSprite( string strSprite ) {
			Sprite buffer;
			if( s_dictSprites.TryGetValue(strSprite,out buffer) )
				return buffer;
			return null;
		}

		public static SpriteFont FindFont( string strFont ) {
			SpriteFont buffer;
			if( s_dictFonts.TryGetValue(strFont,out buffer) )
				return buffer;
			return s_dictFonts["Default"];
		}

		// ----------

		/*private void GamerSignedIn( object sender, SignedInEventArgs e ) {
			PlayerController controller = new PlayerController( e.Gamer );

			if( controller.ControllingIndex == PlayerIndex.One )
				Globals.LocalPlayer = controller;
		}

		private void GamerSignedOut( object sender, SignedOutEventArgs e ) {
			if( Globals.Galaxy != null )
				Globals.Galaxy.OnPlayerLeave( PlayerController.Players[e.Gamer] );

			PlayerController.RemoveController( e.Gamer );
		}*/
	}
}
